package socks

import (
	"net"
	"strconv"
	"sync"
)

type enum_callback func(conn *SockConn) bool

type SocketServer struct {
	sockBase
	server          net.Listener
	rwMtx           sync.RWMutex
	connections     map[int32]*SockConn
	port            uint16
	isOpen          bool
	connectionCount int32
}

// override
func (ss *SocketServer) procConnect(conn *SockConn) {
	func() {
		ss.rwMtx.Lock()
		defer ss.rwMtx.Unlock()
		ss.connections[conn.id] = conn
		ss.connectionCount += 1
	}()

	ss.sockBase.procConnect(conn)
}

// override
func (ss *SocketServer) procDisconnect(sockConn *SockConn) {

	func() {
		ss.rwMtx.Lock()
		defer ss.rwMtx.Unlock()
		delete(ss.connections, sockConn.id)
		ss.connectionCount -= 1
	}()

	ss.sockBase.procDisconnect(sockConn)
}

// 遍历函数，返回 false 时遍历终止
func (svr *SocketServer) Foreach(f enum_callback) {
	svr.rwMtx.RLock()
	defer svr.rwMtx.RUnlock()
	for _, v := range svr.connections {
		if !f(v) {
			break
		}
	}
}

var ErrServerIsClosed = NewError("server is closed")

func (ss *SocketServer) process_accept() {
	for {
		conn, err := ss.server.Accept()

		if err != nil {
			ss.procSockError(nil, err)
			break
		}

		if !ss.isOpen {
			break
		}

		sockConn := createSocketConnection(conn)
		go process_connection(ss, sockConn)
	}
}

func (ss *SocketServer) Close() {
	if ss.isOpen {
		ss.server.Close()
		ss.rwMtx.RLock()
		defer ss.rwMtx.RUnlock()

		for _, v := range ss.connections {
			v.Disconnect()
		}
		ss.isOpen = false
	}
}

func (ss *SocketServer) GetConnectCount() int32 {
	return ss.connectionCount
}

// 异步发送队列里面的数据，避免主线程阻塞
func (s *SocketServer) SendQueueDatas() {
	if s.isOpen {
		s.rwMtx.RLock()
		defer s.rwMtx.RUnlock()
		for _, c := range s.connections {
			c.SendQueueDatas()
		}
	}
}

func (ss *SocketServer) Open() error {
	if !ss.isOpen {
		ss.isOpen = true

		tcpServer, err := net.Listen("tcp", ":"+strconv.Itoa(int(ss.port)))
		if err != nil {
			return NewSockErr("SocketServer.Open, listen eror:", err)
		}
		ss.server = tcpServer

		go ss.process_accept()
	}
	return nil
}

func NewSocketServer(listenPort uint16) *SocketServer {
	server := &SocketServer{
		port:        listenPort,
		connections: make(map[int32]*SockConn),
	}

	return server
}
